﻿/*!
* 开始写个html5的游戏引擎,当然只是简单的2D显示,事件,图形等游戏引擎元素
* 基于html5 canvas画布为渲染
* jQuery JavaScript Library v1.7.1
* http://jquery.com/
* by byz
*/

(function (win, undefined) {
    var _F5Frame = {
        init: function (id, options) {
            this.FPS = 30;
            this.SECONDSBETWEENFRAMES = 1 / this.FPS;
            this.canvasName = id || 'canvas'; //画布id
            this.ContName = 'container'; //控制器id(div)
            this.ContNameID = '#' + this.ContName;
            //alert(this.canvasName);

            options = options || {};
            _w = options.width || 800;
            _h = options.height || 600;
            //创建div
            this.ContainerDiv = document.createElement("div");
            this.ContainerDiv.setAttribute("id", this.ContName);
            this.ContainerDiv.style.border = "1px solid";
            document.body.appendChild(this.ContainerDiv);
            //创建画布
            this.canvas = document.createElement("canvas");
            this.canvas.innerHTML = "请使用支持canvas的浏览器查看(google,firefox)";
            this.canvas.id = this.canvasName;
            this.ContainerDiv.appendChild(this.canvas); /**/
            this.context2D = this.canvas.getContext('2d');

            //设置div大小
            $("#" + this.canvasName).css("width", _w);
            $("#" + this.canvasName).css("height", _h);
            //设置画布大小
            this.canvas.setAttribute("height", _h);
            this.canvas.setAttribute("width", _w);
            //设置画面居中
            offx = (document.body.scrollWidth - _w) / 2; //x偏移量
            offy = 0; //y偏移量
            $(this.ContNameID).css("margin-left", offx);
            $(this.ContNameID).css("margin-top", offy);
            $(this.ContNameID).css("position", "absolute");
            offx = this.ContainerDiv.offsetLeft;
            offy = this.ContainerDiv.offsetTop;

            //****   事件初始化
            //鼠标点击(左、中键)
            $(this.ContNameID).click(function (e) { F5Frame.click(e); });
            //鼠标点击(右键)
            $(this.ContNameID).on("contextmenu", function (e) {
                //在这里书写代码，构建个性右键化菜单 
                F5Frame.click(e);
                //取消默认的右键菜单 
                return false;
            });

            //鼠标移动
            $(this.ContNameID).mousemove(function (e) { F5Frame.mousemove(e); });
            $(this.ContNameID).mousedown(function (e) { F5Frame.mousedown(e); });
            $(this.ContNameID).mouseup(function (e) { F5Frame.mouseup(e); });

            //键盘事件:需要绑定body
            $('body').keydown(function (e) { F5Frame.keydown(e); });
            $('body').keyup(function (e) { F5Frame.keyup(e); });
            $('body').keypress(function (e) { F5Frame.keypress(e); });
            /******/


            //显示宽度
            this._screenWidth = options.width || 800;
            //显示高度
            this._screenHeight = options.height || 600;
            //画面偏移
            this._offx = offx;
            this._offy = offy;

            this.backBuffer = document.createElement('canvas');
            this.backBuffer.width = this.canvas.width;
            this.backBuffer.height = this.canvas.height;
            this.backBufferContext2D = this.backBuffer.getContext('2d');

            /** 保存游戏中对象的数组*/
            this.gameObjects = new MapClass();
            /** 对象索引,累加*/
            this.gameOjbectsIndex = 0;
            /** 保存游戏窗口*/
            this.gameGameForms = new MapClass();
            /** 上一次帧被渲染的时间*/
            this.lastFrame = new Date().getTime();

            //已经运行的时间
            this.currentTime;

            //鼠标位置
            this._mousex;
            this._mousey;

            //当前拾取
            this._pickObj = null;
            //当前拾取(持续
            this._pickObjs = null;
            //当前点击
            this._cdownObjs = null;

            //渲染主循环
            setInterval(function () { F5Frame.frame(); }, Math.floor(this.SECONDSBETWEENFRAMES * 1000));
        },
        /**
        *生成命名空间,并执行相应操作
        **/
        register: function (nameSpace, func) {
            var nsArr = nameSpace.split(".");
            var parent = win;
            for (var i = 0, len = nsArr.length; i < len; i++) {
                (typeof parent[nsArr[i]] == 'undefined') && (parent[nsArr[i]] = {});
                parent = parent[nsArr[i]];
            }
            if (func) {
                func.call(parent, this);
            }
            return parent;
        }
    }

    win["F5Frame"] = _F5Frame;

    /**
    *
    *主管理
    *
    **/
    F5Frame.register("F5Frame", function (cg) {
        /**
        *原型继承对象
        **/
        this.inherit = function (child, parent) {
            var func = function () { };
            func.prototype = parent.prototype;
            child.prototype = new func();
            child.prototype.constructor = child;
            child.prototype.parent = parent;
        };

        //帧更新
        this.frame = function () {
            // 计算从上一帧到现在的时间
            var thisFrame = new Date().getTime();
            var dt = (thisFrame - F5Frame.lastFrame) / 1000;
            F5Frame.lastFrame = thisFrame;
            F5Frame.currentTime += thisFrame;

            // 清理绘制上下文
            F5Frame.backBufferContext2D.clearRect(0, 0, F5Frame.backBuffer.width, F5Frame.backBuffer.height);
            F5Frame.context2D.clearRect(0, 0, F5Frame.canvas.width, F5Frame.canvas.height);

            // 首先更新所有游戏对象
            for (x in F5Frame.gameObjects.toArray()) {
                if (F5Frame.gameObjects.getk(x).frame) {
                    F5Frame.gameObjects.getk(x).frame(dt, F5Frame.backBufferContext2D);
                }
            }

            // 然后绘制所有游戏对象
            for (x in F5Frame.gameObjects.toArray()) {
                if (F5Frame.gameObjects.getk(x).draw) {
                    F5Frame.gameObjects.getk(x).draw(dt, F5Frame.backBufferContext2D);
                }
            }
            //普通文字
            fps = Math.round(1 / dt);

            F5Frame.backBufferContext2D.fillStyle = "#82B1FF";
            F5Frame.backBufferContext2D.font = "10pt 宋体";
            F5Frame.backBufferContext2D.fillText("帧数(fps):" + fps, 10, 10);
            F5Frame.backBufferContext2D.fillText("鼠标位置: (" + F5Frame._mousex + " , " + F5Frame._mousey + ")", 10, 25);

            F5Frame.backBufferContext2D.fillText("对象数(image):" + F5Frame.gameObjects.count(), 120, 10);
            F5Frame.backBufferContext2D.fillText("拾取对象数(image):" + F5Frame.picklist().length, 250, 10);

            var imageData = F5Frame.context2D.getImageData(0, 0, F5Frame._screenWidth, F5Frame._screenHeight);
            var data = imageData.data;
            //F5Frame.backBufferContext2D.fillText(data[this._mousex * 3 + F5Frame._screenWidth * this._mousey], 10, 150);

            //拾取事件判定
            pickobj = F5Frame.pickfirst();
            if (pickobj) {
                for (x in F5Frame.gameObjects.toArray()) {
                    if (F5Frame.gameObjects.getk(x).getID() != pickobj.getID()) {
                        if (F5Frame.gameObjects.getk(x).set_pick) {
                            F5Frame.gameObjects.getk(x).set_pick(false);
                        }
                    }
                }

                pickobj.set_pick(true);
                F5Frame.backBufferContext2D.fillText("拾取对象:" + pickobj.getID() + " " + pickobj.getX() + " " + pickobj.getY() +
                " " + pickobj.getConterX() + " " + pickobj.getConterY() + " " + pickobj.zLayer, 160, 30);
            }
            else {
                for (x in F5Frame.gameObjects.toArray()) {
                    if (F5Frame.gameObjects.getk(x).set_pick) {
                        F5Frame.gameObjects.getk(x).set_pick(false);
                    }
                }
            }

            //用户密码
            //F5Frame.context2D.fillText("用户名: " + localStorage.loginname + " 昵称:" + (sessionStorage.nickname), 20, 60);
            //艺术字
            /*F5Frame.context2D.font = "10pt 微软雅黑";
            F5Frame.context2D.strokeStyle = "blue"; // stroke color    
            F5Frame.context2D.strokeText("艺术字:蓝色雅黑", 20, 12);*/

            // 将后台缓冲复制到当前显示的画布
            F5Frame.context2D.drawImage(F5Frame.backBuffer, 0, 0);
            //F5Frame.context2D.restore();
        }

        /**
        向gameObjects集合中添加一个GameObject
        @param gameObject The object to add
        */
        this.addGameObject = function (gameObject) {
            //索引+1 保存所有对象的索引唯一
            F5Frame.gameOjbectsIndex += 1; 2
            gameObject.setID(F5Frame.gameOjbectsIndex);

            if (gameObject._isform) {
                this.addGameForm(gameObject);
            }

            F5Frame.gameObjects.add(gameObject._id, gameObject);
            this.sortGameObject();
        };
        /**
        对gameObjects集合进入排序
        @sort The gameObjects
        */
        this.sortGameObject = function () {
            F5Frame.gameObjects.sort();
        }
        /**
        从gameObjects集合中删除一个GameObject
        @param gameObject The object to remove
        */
        this.removeGameObject = function (gameObject) {
            F5Frame.gameObjects.del(gameObject.getID());

            if (gameObject._isform) {
                this.removeGameForm(gameObject);
            }
        }

        /**
        向gameGameForms集合中添加一个GameObject
        @param gameObject The object to add
        */
        this.addGameForm = function (gameObject) {
            //索引+1 保存所有对象的索引唯一
            F5Frame.gameGameForms.add(gameObject._id, gameObject);

            gameObject.setLayer(F5Frame.gameGameForms.count());

            gameObject.click(this.sortGameForm, { arg1: gameObject });

            this.sortGameForm(gameObject);
        };
        /**
        对gameGameForms集合进行排序,传入的参数是在最上面的窗口,然后把其它的窗口放置于此窗口下面
        @sort The gameObjects
        */
        this.sortGameForm = function (gameObject, gameForms) {
            if (gameObject) {
                gameForms = F5Frame.gameGameForms;
                //传递进来的窗口与最前面的窗口交换层级,
                gameForms.sort_layer();
                if (gameForms.count() > 0) {
                    templayer = gameObject.zLayer;
                    gameObject.setLayer(gameForms.getk(0).zLayer + 1);
                    //gameForms.getk(0).setLayer(templayer); /**/
                }
                F5Frame.sortGameObject();

                //重置层级
                gameForms.sort_layer();
                for (x in gameForms.toArray()) {
                    gameForms.getk(x).setLayer(gameForms.count() - x + 1);
                }

                F5Frame.sortGameObject();
            }
        }
        /**
        从gameGameForms集合中删除一个GameObject
        @param gameObject The object to remove
        */
        this.removeGameForm = function (gameObject) {
            F5Frame.gameGameForms.del(gameObject.getID());
        }
        this.hideGameForm = function (gameObject) {
            gameObject.hide();
            //alert(gameObject.getID());
        }


        //鼠标点击
        this.click = function (e) {
            for (x in F5Frame.gameObjects.toArray()) {
                if (F5Frame.gameObjects.getk(x)._click) {
                    F5Frame.gameObjects.getk(x)._click(F5Frame._mousex, F5Frame._mousey, e.which);
                }
            }
            //e.which 1 = 鼠标左键；2 = 鼠标中键；3 = 鼠标右键。
        }
        //键盘按下
        this.mousedown = function (e) {
            F5Frame._pickObjs = null;
            //获得当前选中并且能拖动的实体
            var x = F5Frame.gameObjects.count() - 1;
            for (; x >= 0; x--) {
                obj = F5Frame.gameObjects.getk(x);
                if (obj.jugePick(F5Frame._mousex, F5Frame._mousey)) {
                    if (obj.drag()) {
                        F5Frame._pickObjs = obj;
                    }
                    F5Frame._cdownObjs = obj;
                    F5Frame._cdownObjs.on_mousedown(F5Frame._mousex, F5Frame._mousey);
                    break;
                }
            }
        }
        //键盘按起
        this.mouseup = function (e) {
            if (F5Frame._pickObjs) {
                //更新鼠标状态
                document.body.style.cursor = 'default';
                F5Frame._pickObjs = null;
            }
            if (F5Frame._cdownObjs) {
                F5Frame._cdownObjs.on_mouseup(F5Frame._mousex, F5Frame._mousey);
                F5Frame._cdownObjs = null;
            }
        }
        //鼠标移动
        this.mousemove = function (e) {
            //得到鼠标偏移量
            offx = F5Frame._mousex - (e.pageX - F5Frame._offx);
            offy = F5Frame._mousey - (e.pageY - F5Frame._offy);
            //更新全局鼠标位置
            F5Frame._mousex = (e.pageX - F5Frame._offx);
            F5Frame._mousey = (e.pageY - F5Frame._offy);
            //拖动当前鼠标的对象
            if (F5Frame._pickObjs) {
                F5Frame._pickObjs.moveOff(offx, offy);
            }
        }
        //键盘按下
        this.keydown = function (e) {
        }
        //键盘按起
        this.keyup = function (e) {
        }
        //键盘释放
        this.keypress = function (e) {
            //document.getElementById(debugmsg).innerHTML = "按键: " + e.keyCode;
        }
        //返回拾取到的所有对象
        this.picklist = function (first) {
            var first = first || false;
            var objlist = new Array();

            var x = F5Frame.gameObjects.count() - 1;
            for (; x >= 0; x--) {
                obj = F5Frame.gameObjects.getk(x);
                if (obj.jugePick(F5Frame._mousex, F5Frame._mousey)) {
                    if (first)
                        return obj;
                    objlist.push(obj);
                }
            }
            if (first)
                return null;
            return objlist;
        }
        //返回拾取到的第一个对象
        this.pickfirst = function () {
            return this.picklist(true);
        }
    });

    /**
    *
    *基本工具函数
    *
    **/
    F5Frame.register("F5Frame.core", function (cg) {
        /**
        是否为undefined
        **/
        this.isUndefined = function (elem) {
            return typeof elem === 'undefined';
        },
        /**
        是否为数组
        **/
		this.isArray = function (elem) {
		    return Object.prototype.toString.call(elem) === "[object Array]";
		};
        /**
        是否为Object类型
        **/
        this.isObject = function (elem) {
            return elem === Object(elem);
        };
        /**
        是否为字符串类型
        **/
        this.isString = function (elem) {
            return Object.prototype.toString.call(elem) === "[object String]";
        };
        /**
        是否为数值类型
        **/
        this.isNum = function (elem) {
            return Object.prototype.toString.call(elem) === "[object Number]";
        };
        /**
        *复制对象属性
        **/
        this.extend = function (destination, source, isCover) {
            var isUndefined = this.isUndefined;
            (isUndefined(isCover)) && (isCover = true);
            for (var name in source) {
                if (isCover || isUndefined(destination[name])) {
                    destination[name] = source[name];
                }

            }
            return destination;
        };
        /**
        *原型继承对象
        **/
        this.inherit = function (child, parent) {
            var func = function () { };
            func.prototype = parent.prototype;
            child.prototype = new func();
            child.prototype.constructor = child;
            child.prototype.parent = parent;
        };

    });

    /**
    *
    *资源加载器
    *
    **/
    F5Frame.register("F5Frame", function (cg) {

        /**
        *图像加载完毕的处理程序
        **/
        var imgLoad = function (self) {
            return function () {
                self.loadedCount += 1;
                self.loadedImgs[this.srcPath] = this;
                this.onLoad = null; 				//保证图片的onLoad执行一次后销毁
                self.loadedPercent = Math.floor(self.loadedCount / self.sum * 100);
                self.onLoad && self.onLoad(self.loadedPercent);

                //alert(this.srcPath + " " + self.loadedPercent + " " + F5Frame.loader.loadedImgs[this.srcPath]);
                if (self.loadedPercent === 100) {

                    self.loadedCount = 0;
                    self.loadedPercent = 0;
                    loadingImgs = {};

                    F5Frame.loader.begFunc();
                }
            }
        }
        /**
        *图像加载器
        **/
        var loader = {
            sum: 0, 		//图片总数
            loadedCount: 0, //图片已加载数
            loadingImgs: {}, //未加载图片集合
            loadedImgs: {}, //已加载图片集合
            /**
            *图像加载，之后启动游戏
            **/
            start: function (src, begFunc) {//可传入src数组或单个src "xxx.jpg" or ["xxx.jpg","ggg,gif","www.png"]
                if (cg.core.isArray(src)) {
                    this.sum = src.length;
                    for (var i = 0, len = src.length; i < len; i++) {
                        this.begFunc = begFunc;
                        this.loadingImgs[src[i]] = new Image();
                        this.loadingImgs[src[i]].onload = imgLoad(this);
                        this.loadingImgs[src[i]].src = src[i];
                        this.loadingImgs[src[i]].srcPath = src[i]; //没有经过自动变换的src
                    }

                }

            }

        }


        this.loader = loader;
    });
})(window, undefined);